package com.Cfeng.XiaohuanChat.controller;

import com.Cfeng.XiaohuanChat.domain.Dtree;
import com.Cfeng.XiaohuanChat.domain.Resp;
import com.Cfeng.XiaohuanChat.entity.UserFile;
import com.Cfeng.XiaohuanChat.service.UserMinIOFileService;
import com.alibaba.fastjson.JSON;
import com.indCfeng.minio.MinioService;
import lombok.RequiredArgsConstructor;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.userdetails.User;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.Principal;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @author Cfeng
 * @date 2022/8/12
 * 操作Minio文件的处理器
 * 文件分为文件和文件夹，通过isDir分别，前台传入的dirIds为路径拼接的一个完整的路径，用户可以自由创建目录，删除目录等
 */

@RequiredArgsConstructor
@RestController
@RequestMapping("/file")
public class MinioFileController {

    private final UserMinIOFileService minIOFileService;

    private final MinioService minioService;

    /**
     * 获取当前目录下面的文件列表
     * @param userFile 传入的参数的接收实体，主要就是接收其dirIds，当前目录id
     * 匹配默认的和/list
     */
    @GetMapping({"","/list"})
    public Resp<List<UserFile>> getFileList(UserFile userFile) {
        List<UserFile> userFileList = minIOFileService.getFileList(userFile);
        return Resp.ok(userFileList);
    }

    @GetMapping("/getTree")
    public String getTree(UserFile userFile) {
        List<Dtree> list = minIOFileService.getTreeList(userFile);
        return JSON.toJSONString(Resp.ok(list));
    }

    /**
     * 获取树目录列表
     * @param userFile
     * @return
     */
    @GetMapping("/getDirTree")
    public String getDirTree(UserFile userFile) {
        List<Dtree> list = minIOFileService.getDirTreeList(userFile);
        return JSON.toJSONString(Resp.ok(list));
    }

    /**
     * 获取当前id的完整目录列表
     * @param id
     * @return
     */
    @GetMapping("/getDirs")
    public Resp<Map> getDirs(Long id) {
        Map<String,Object> map = minIOFileService.getDirs(id);
        return Resp.ok(map);
    }

    //principal securty框架会自动注入principal对象进入容器供该处理器方法使用
    @PostMapping({"","/upload"})
    public Resp<String> uploadFile(Principal principal ,@RequestParam("file") MultipartFile multipartFile, String dirIds) throws Exception {
        //保存文件
        if(multipartFile.isEmpty()) {
            return Resp.failed("保存文件失败");
        }
        minIOFileService.addFile(principal,multipartFile,dirIds);
        return Resp.ok("文件上传成功");
    }

    @GetMapping("/deleteByIds")
    public Resp<String> deleteFile(@RequestParam("id") long fileId) throws Exception {
        //删除文件
        if(minIOFileService.deleteFile(fileId)) {
            return Resp.ok("删除文件成功");
        }
        return Resp.failed("文件删除失败，稍后重试");
    }

    @PostMapping("/deleteFile")
    public Resp<String> deleteFile(String url) throws Exception {
        //删除文件
        if(minIOFileService.deleteFileByUrl(url)) {
            return Resp.ok("删除文件成功");
        }
        return Resp.failed("文件删除失败，稍后重试");
    }

    //返回响应体，这里使用spring封装的实体
    @GetMapping(path = "/{userName}/{fileName}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public ResponseEntity<Resource> download(Principal principal, @PathVariable("userName") String userName, @PathVariable("fileName") String fileName) throws Exception {
        //下载文件，之前的普通的存储也是返回的Resource
        if(!principal.getName().equals(userName)) {
            throw new RuntimeException("权限不足，你只能下载自己上传的文件");
        }
        Optional<UserFile> fileOptional = minIOFileService.getFile(principal.getName(), fileName);
        //获取文件元素据，构造object请求
        if(fileOptional.isPresent()) {
            UserFile userFile = fileOptional.get();
            String objectName = userFile.getObjectName();
            //构造返回的请求体，放入资源
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.add(HttpHeaders.CONTENT_DISPOSITION,"attachment;filename=" + URLEncoder.encode(userFile.getFileName(), StandardCharsets.UTF_8));
            return ResponseEntity.ok()
                    .headers(httpHeaders)
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .body(new InputStreamResource(minioService.getObject(objectName)));
        }
        throw new RuntimeException("文件不存在");
    }

    /**
     * 新增文件夹
     */
    @PostMapping("/addFolder")
    public Resp<String> addFolder(UserFile userFile) {
        if(minIOFileService.addFolder(userFile)) {
            return Resp.ok("添加成功");
        }
        return Resp.failed("添加失败");
    }

    /**
     * 修改名称
     */
    @PostMapping("/updateName")
    public Resp<String> updateByName(UserFile userFile) {
        if(minIOFileService.updateByName(userFile)) {
            return Resp.ok("修改成功");
        }
        return Resp.failed("修改失败");
    }

    /**
     * 移动文件
     */
    @PostMapping("/move")
    public  Resp<String> move(String ids,Long parentId) {
        if(minIOFileService.moveFile(ids,parentId)) {
            return Resp.ok("移动成功");
        }
        return Resp.failed("移动失败");
    }


}
